Сохранение объектов. Исключение событий из serialization-графа
В процессе исправления ошибок в одном из проектов после реализации в документе обработки сообщений об изменениях в модели перестал работать механизм копирования-вставки через буфер обмена. Работа с буфером обмена реализована стандартным для .NET способом.
IDataObject dataObj = new DataObject(); dataObj.SetData(CardDataFormat, false, modelObject); Clipboard.SetDataObject(dataObj, false);
При вызове SetData производится сохранение объекта «modelObject» (одного из объектов иерархической модели, которая содержится в документе) посредством стандарного механизма сериализации. При сохранении объекта модели, производится сохранение всего графа объектов, на которые ссылается данный объект и его предки, включая модель, за исключением полей, помеченных атрибутом [NonSerialized].
The target objects for the NonSerializedAttribute attribute are public and private fields of a serializable class. By default, classes are not serializable unless they are marked with SerializableAttribute. During the serialization process all the public and private fields of a class are serialized by default. Fields marked with NonSerializedAttribute are excluded during serialization.
После того, как в класс модели (см. вставку кода ниже) было добавлено событие ModelChanged в граф сохранения включился и документ. После чего попытка записи объекта модели начала приводить к попытке записи документа, не помеченого атрибутом [Serializable] и возникновению исключения. Явное указание атрибута [NonSerialized] для события приводит к ошибке компиляции. Однако, при внимательном чтении документации выяснилась очень интересная деталь. Для исключения событий из графа сериализации и, соответственно, «развязывания» объектов модели и документа, которые «связаны» только обработчиком события, нужно специальным образом [field:NonSerializedAttribute()] установить для данного события атрибут [NonSerialized].
To apply the NonSerializedAttribute class to an event, set the attribute location to field, as shown in the following C# code.
[field:NonSerializedAttribute()]
public event ChangedEventHandler Changed;
Фрагменты кода модели и документа.
[Serializable] public partial class DraftModel : IObjectModel, IDeserializationCallback { private Block _block; //Исключение события из графа сериализации. [field: NonSerialized] public event Action ModelChanged; //фрагмент модели... } public abstract class DraftDocument : Document { private DraftModel _model; protected DraftDocument(string name) : this(name, new DraftModel()) { _model = new DraftModel(); //назначение обработчика события приведёт к тому, что при сохранении //модели также будет сохранятся и документ, что приведёт к исключению, т.к. //данный класс не помечен как сериализуемый. _model.ModelChanged += new Action(OnModelChanged); } public DraftModel DraftModel { get { return _model; } } private void OnModelChanged() { //... } //фрагмент документа... }